#include "PhysXWorld.h"
#include "logwriter.h"

using namespace NxOgre::Enums;

PhysXWorld::PhysXWorld(void)
{
	lBoxes = new std::vector<Critter::Body*>();
	lActors = new std::vector<ActorEntitySceneNode*>();
}

//---------------------------------------------------------------------------------------------------------

PhysXWorld::~PhysXWorld(void)
{
	clearAll();
	delete lBoxes;
	delete lActors;
}

//---------------------------------------------------------------------------------------------------------

void PhysXWorld::clearAll(void)
{

	int nSize = lActors->size();
	for(int i=0;i<nSize;i++)
	{
		delete lActors->at(i);
	}
	lActors->clear();
}

//---------------------------------------------------------------------------------------------------------

void PhysXWorld::fireAllEmitters(void)
{
	extern AppSettings settings;

	int nSize = lActors->size();
	for(int i=0;i<nSize;i++)
	{
		ActorEntitySceneNode *temp = lActors->at(i);
		if(temp->getActorType() == ActorEntitySceneNode::Emitter_Holder)
		{
			Lake* holder = ((Lake*)temp);
			holder->fireAllEmitters(settings.waterSettings.mParticleSize);
		}
	}
}

//---------------------------------------------------------------------------------------------------------

void PhysXWorld::setStaticAllEmitters(void)
{
	int nSize = lActors->size();
	for(int i=0;i<nSize;i++)
	{
		ActorEntitySceneNode *temp = lActors->at(i);
		if(temp->getActorType() == ActorEntitySceneNode::Emitter_Holder)
		{
			Lake* holder = ((Lake*)temp);

			int nEmitters = holder->getNumEmitters();
			for(int j=0;j<nEmitters;j++)
			{
				holder->getEmitter(j)->setStatic();
			}
		}
	}
}

//---------------------------------------------------------------------------------------------------------

void PhysXWorld::createScenery(WorldEnums::eSceneryObjects sceneryType, NxOgre::Vec3 position, NxOgre::Scene* mScene, Ogre::SceneManager *mSceneMgr)
{
	Ogre::String uniqeId = Ogre::StringConverter::toString(lActors->size());

	ActorEntitySceneNode *newScenery = sceneryFactory.createScenery(sceneryType, uniqeId, position, mScene, mSceneMgr);
	lActors->push_back(newScenery);

}

//---------------------------------------------------------------------------------------------
void PhysXWorld::attachWaterEmitter(Lake* lake, Critter::RenderSystem*  mRenderSystem, Ogre::SceneManager *mSceneMgr, NxOgre::Real PosX, NxOgre::Real PosY, NxOgre::Real PosZ)
{
	extern AppSettings settings;

		  WaterEmitter *waterEmitter = new WaterEmitter("", mRenderSystem, mSceneMgr);
				  waterEmitter->mMaxParticles = settings.waterSettings.mMaxParticles;
					waterEmitter->mKernelRadiusMultiplier = settings.waterSettings. mKernelRadiusMultiplier;
					waterEmitter->mRestParticlesPerMetre = settings.waterSettings. mRestParticlesPerMetre;
					waterEmitter->mPacketSizeMultiplier = settings.waterSettings. mPacketSizeMultiplier;
					waterEmitter->mMotionLimitMultiplier = settings.waterSettings. mMotionLimitMultiplier;
					waterEmitter->mCollisionDistanceMultiplier = settings.waterSettings. mCollisionDistanceMultiplier;
					waterEmitter->mStiffness = settings.waterSettings. mStiffness;
					waterEmitter->mViscosity = settings.waterSettings. mViscosity;
					waterEmitter->mRestDensity = settings.waterSettings. mRestDensity;
					waterEmitter->mParticleLifetime = settings.waterSettings. mParticleLifetime;
					waterEmitter->mRate = settings.waterSettings. mRate;
					waterEmitter->mFluidSpeed = settings.waterSettings.mFluidSpeed;
					waterEmitter->mReplusionCoefficient = settings.waterSettings. mReplusionCoefficient;
					waterEmitter->mDimensionX = settings.waterSettings.mDimensionX;
					waterEmitter->mDimensionY = settings.waterSettings.mDimensionY;
					waterEmitter->setPosition(NxOgre::Vec3(PosX,PosY + settings.waterSettings.mStartHeight,PosZ));
					waterEmitter->mParticleSize = settings.waterSettings.mParticleSize;


	    Ogre::String holderName = lake->getName();
		Ogre::String emitterName = ":WaterEmitter";
		emitterName.append(Ogre::StringConverter::toString(lake->getNumEmitters()));
		waterEmitter->setName(holderName.append(emitterName));
		lake->attachEmitter(waterEmitter);
}

//---------------------------------------------------------------------------------------------

void PhysXWorld::moveSceneryObject(int actorIndex, WorldEnums::eAngle byAngle, Ogre::Real value)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex <= (lActors->size()-1)))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);
			Ogre::Vector3 oldPosition = actor->getSceneNode()->getPosition();

			if(!actor->isPhisical)
			{
				switch(byAngle)
				{
				case WorldEnums::Angle_X:
					actor->getSceneNode()->setPosition(oldPosition.x + value,oldPosition.y,oldPosition.z);
					break;
				case WorldEnums::Angle_Y:
					actor->getSceneNode()->setPosition(oldPosition.x,oldPosition.y + value,oldPosition.z);
					break;
				case WorldEnums::Angle_Z:
					actor->getSceneNode()->setPosition(oldPosition.x,oldPosition.y,oldPosition.z + value);
					break;
				}
			}
		}
	}
}

//---------------------------------------------------------------------------------------------

void PhysXWorld::scaleSceneryObject(int actorIndex, Ogre::Real value)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex <= (lActors->size()-1)))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);

			if(!actor->isPhisical)
			{
				Ogre::Vector3 oldScale = actor->getSceneNode()->getScale();
				actor->getSceneNode()->setScale(oldScale.x+value,oldScale.y+value,oldScale.z+value);
			}
		}
	}
}

//---------------------------------------------------------------------------------------------

void PhysXWorld::setSceneryObjectScale(int actorIndex, Ogre::Vector3 scale)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex <= (lActors->size()-1)))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);

			if(!actor->isPhisical)
			{
				actor->getSceneNode()->setScale(scale);
			}
		}
	}
}

//---------------------------------------------------------------------------------------------

void PhysXWorld::rotateSceneryObject(int actorIndex, int value)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex <= (lActors->size()-1)))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);

			if(!actor->isPhisical)
			{
				actor->getSceneNode()->rotate(Ogre::Vector3(0,1,0),Ogre::Degree(value));
			}
		}
	}
}


//---------------------------------------------------------------------------------------------

void PhysXWorld::setSceneryObjectRotation(int actorIndex, Ogre::Quaternion rotation)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex <= (lActors->size()-1)))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);

			if(!actor->isPhisical)
			{
				actor->getSceneNode()->setOrientation(rotation);
			}
		}
	}
}

//---------------------------------------------------------------------------------------------

void PhysXWorld::deleteSceneryObject(int actorIndex)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex <= (lActors->size()-1)))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);
			
			std::vector<ActorEntitySceneNode*>::iterator it = lActors->begin();
			for(int i=0;i<=actorIndex;i++)
			{
				if(i==actorIndex)
				{
					lActors->erase(it);
				}
			}

			delete actor;
			actor = 0;
		}
	}
}


//---------------------------------------------------------------------------------------------

Ogre::StringVector PhysXWorld::returnActorNames(void)
{
	Ogre::StringVector actorNames;
	for(int i=0;i<lActors->size();i++)
	{
		actorNames.push_back(lActors->at(i)->getName());
	}

	return actorNames;
}

//---------------------------------------------------------------------------------------------

Ogre::StringVector PhysXWorld::returnHolderActorNames(void)
{
	Ogre::StringVector names;
	int nSize = lActors->size();
	for(int i=0;i<nSize;i++)
	{
		ActorEntitySceneNode *temp = lActors->at(i);
		if(temp->getActorType() == ActorEntitySceneNode::Emitter_Holder)
		{
			Lake* holder = ((Lake*)temp);
			names.push_back(holder->getName());
			
		}
	}

	return names;
}

//---------------------------------------------------------------------------------------------

Ogre::StringVector PhysXWorld::returnEmitterNames(int holderIndex)
{
	Ogre::StringVector names;
	int index = -1;
	int nSize = lActors->size();
	for(int i=0;i<nSize;i++)
	{
		ActorEntitySceneNode *temp = lActors->at(i);
		if(temp->getActorType() == ActorEntitySceneNode::Emitter_Holder)
		{
			index++;

			if(index == holderIndex)
			{
				Lake* holder = ((Lake*)temp);

				int nEmitters = holder->getNumEmitters();
				for(int j=0;j<nEmitters;j++)
				{
					names.push_back(holder->getEmitter(j)->getName());
				}
			}

		}
	}

	return names;
}

//---------------------------------------------------------------------------------------------

bool PhysXWorld::isHolderActor(int actorIndex)
{
	if(lActors->size()>0)
	{
		if((actorIndex >=0 ) && (actorIndex < lActors->size()))
		{
			ActorEntitySceneNode *actor = lActors->at(actorIndex);
			
			if(actor->getActorType() == ActorEntitySceneNode::Emitter_Holder)
			{
				return true;
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------------------------

Lake *PhysXWorld::getHolderActor(int holderActorIndex)
{
	int index = -1;
	int nSize = lActors->size();
	for(int i=0;i<nSize;i++)
	{
		ActorEntitySceneNode *temp = lActors->at(i);
		if(temp->getActorType() == ActorEntitySceneNode::Emitter_Holder)
		{
			index++;

			if(index == holderActorIndex)
			{
				Lake* holder = ((Lake*)temp);

				return holder;
			}

		}
	}

	return 0;
}

//---------------------------------------------------------------------------------------------